<template>
	<view class="content">
		<!-- 验证码主体 -->
		<view v-for="(item, index) in list" :key="index" class="list-item" @longtap="delCode(index)">
			<view class="list-item-left">
				<view class="name" @click="editName(index)">{{item.name}}</view>
				<view class="code" @click="copyCode(item.code)">{{item.code}}</view>
			</view>
			<view class="list-item-right">
				<view class="item-time"
							:class="{'primary' : 10 < second, 'warning' : 5 < second && 10 >= second, 'danger' : 5 >= second}">
					{{second}}
				</view>
			</view>
		</view>

		<!-- 空状态 -->
		<view class="empty-box" v-show="0 === list.length">
			<view class="title">设置首个账号</view>
			<view class="title-2">使用双重身份验证设置（Google 或第三方服务）中显示的二维码或设置密钥。</view>
			<view class="empty-box-btn">
				<view class="empty-box-btn-item" @click="scanCode">
					<uni-icons class="icon" type="scan" color="#2979ff" size="30"></uni-icons>
					<view>扫描二维码</view>
				</view>
				<view class="empty-box-btn-item" @click="inputCode">
					<uni-icons class="icon" type="compose" color="#18bc37" size="30"></uni-icons>
					<view>输入设置密钥</view>
				</view>
			</view>
		</view>

		<!-- 悬浮按钮 -->
		<uni-fab :content="fabContent" horizontal="right" vertical="bottom" direction="horizontal"
						 @trigger="fabTrigger"></uni-fab>

		<!-- 手动输入框 -->
		<uni-popup ref="popup" background-color="#fff">
			<uni-section class="mb-50" title="输入设置密钥"></uni-section>
			<uni-easyinput class="mb-50" v-model="input.name" placeholder="请输入名称"></uni-easyinput>
			<uni-easyinput class="mb-50" v-model="input.key" placeholder="请输入密钥"></uni-easyinput>
			<button type="primary" @click="inputSubmit">提交</button>
		</uni-popup>

		<!-- 修改名称对话框 -->
		<uni-popup ref="editDialog" type="dialog">
			<uni-popup-dialog mode="input" title="修改名称" :value="edit.name" placeholder="请输入内容"
												@confirm="editConfirm"></uni-popup-dialog>
		</uni-popup>

		<!-- 删除对话框 -->
		<uni-popup ref="delDialog" type="dialog">
			<uni-popup-dialog type="warning" cancelText="取消" confirmText="确认" title="警告" content="确认删除？"
												@confirm="delConfirm"></uni-popup-dialog>
		</uni-popup>

		<!-- 消息提示 -->
		<uni-popup ref="message" type="message">
			<uni-popup-message :type="message.type" :message="message.text" :duration="2000"></uni-popup-message>
		</uni-popup>
	</view>
</template>

<script>
import {
	sjcl
} from '@/common/sjcl.js'
import {
	getCode
} from '@/common/code_totp.js'
export default {
	data() {
		return {
			list: [],
			fabContent: [{
				iconPath: '/static/scan.png',
				selectedIconPath: '/static/scan.png',
				text: '扫码',
				active: false
			},
				{
					iconPath: '/static/input.png',
					selectedIconPath: '/static/input.png',
					text: '输入',
					active: false
				}
			],
			second: 0,
			delIndex: -1,
			edit: {
				index: -1,
				name: ''
			},
			message: {
				type: '',
				text: ''
			},
			input: {
				name: '',
				key: ''
			}
		}
	},
	onLoad() {
		this.getSecond()
		this.autoCode()
		this.loadData()
	},
	methods: {
    // 获取缓存数据
		loadData() {
			let data = uni.getStorageSync('Auth-data')
			if (data && 0 < data.length) {
				this.list = data
				this.generateCode()
			}
		},
    // 缓存数据
		saveData() {
			uni.setStorageSync('Auth-data', this.list)
		},
    // 悬浮按钮点击事件
		fabTrigger(e) {
			let index = e.index
			if (0 === index) {
				this.scanCode()
			} else {
				this.inputCode()
			}
		},
		// 输入方式
		inputCode() {
			this.$refs.popup.open('top')
		},
    // 输入提交
		inputSubmit() {
			let data = this.input
			if (!data.name) {
				this.showMessage('warning', '请输入名称')
				return false
			}
			if (!data.key) {
				this.showMessage('warning', '请输入密钥')
				return false
			}
			if (this.checkRepeat(data.key)) {
				this.showMessage('error', '密钥重复，添加失败')
				return false
			}
			if (!this.checkKey(data.key)) {
				return false
			}
			this.list.push(data)
			this.saveData()
			this.showMessage('success', '添加成功')
			this.input = {
				name: '',
				key: ''
			}
			this.$refs.popup.close()
		},
		// 扫码方式
		scanCode() {
			let that = this
			uni.scanCode({
				onlyFromCamera: true,
				scanType: ['qrCode'],
				success(res) {
					let result = res.result
					if (!result) {
						that.showMessage('error', '二维码内容为空')
						return false
					}
					if (!result.startsWith('otpauth://totp/')) {
						that.showMessage('error', '二维码内容错误')
						return false
					}
					result = result.replace('otpauth://totp/', '')
					let name = decodeURI(result.split('?')[0])
					let key = result.split('?')[1].replace('secret=', '')
					if (that.checkRepeat(key)) {
						that.showMessage('error', '密钥重复，添加失败')
						return false
					}
					if (!that.checkKey(key)) {
						return false
					}
					let data = {
						name: name,
						key: key,
						code: ''
					}
					that.list.push(data)
					that.saveData()
					that.showMessage('success', '添加成功')
				}
			})
		},
    // 检查秘钥
		checkKey(key) {
			try {
				getCode(sjcl, key, this.getCTime())
				return true
			} catch (e) {
				this.showMessage('error', '秘钥错误，' + e.message)
			}
			return false
		},
    // 检查重复
		checkRepeat(key) {
			let flag = false
			for (let i = 0; i < this.list.length; i++) {
				if (key === this.list[i].key) {
					flag = true
					break
				}
			}
			return flag
		},
    // 提示信息
		showMessage(icon, text) {
      uni.showToast({
        title: text,
        icon: icon
      })
		},
		getSecond() {
			let that = this
			that.readSecond()
			setInterval(function() {
				that.readSecond()
			}, 1000)
		},
		readSecond() {
			let date = new Date();
			let second = date.getSeconds();
			if (30 < second) {
				second = second - 30;
			}
			second = 30 - second
			this.second = 0 === second ? 30 : second;
		},
		getCTime() {
			return Math.floor((new Date() - 0) / 30000)
		},
    // 批量生产code
		generateCode() {
			if (!this.list || 0 === this.list.length) {
				return false
			}
			for (let i = 0; i < this.list.length; i++) {
				let data = this.list[i]
				let time = this.getCTime();
        this.list[i].code = getCode(sjcl, data.key, time)
			}
		},
    // 自动生成code
		autoCode() {
			let that = this
			that.generateCode()
			setInterval(function() {
				that.generateCode()
			}, 1000)
		},
    // 复制code
    copyCode(code) {
      uni.setClipboardData({
        data: code,
        showToast: true
      })
    },
    // 修改用户名
    editName(index) {
      this.edit = {
        index: index,
        name: this.list[index].name
      }
      this.$refs.editDialog.open()
    },
    // 确认修改
		editConfirm(name) {
			if (!name) {
				this.showMessage('error', '请输入名称')
				return false
			}
			this.list[this.edit.index].name = name
			this.saveData()
      this.showMessage('success', '修改成功')
		},
    // 删除数据
		delCode(index) {
			this.delIndex = index
			this.$refs.delDialog.open()
		},
    // 确认删除
		delConfirm() {
			this.list.splice(this.delIndex, 1)
			this.saveData()
		}
	}
}
</script>

<style>
.content {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 0 30rpx;
}

.uni-list {
	width: 100%;
}

.list-item {
	width: 100%;
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 20rpx 0;
	border-bottom: 1rpx solid #b9b9b9;
}

.list-item-left {
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: 0 20rpx;
}

.list-item-right {
	padding: 0 20rpx;
}

.name {
	font-size: 32rpx;
	color: #333;
	margin-bottom: 10rpx;
}

.code {
	font-size: 48rpx;
	color: #2979ff;
	font-weight: bold;
	margin-top: 10rpx;
}

.item-time {
	width: 40rpx;
	height: 40rpx;
	line-height: 40rpx;
	text-align: center;
	font-size: 24rpx;
	border-radius: 50%;
	color: #fff;
}

.primary {
	background-color: #2979ff;
}

.warning {
	background-color: #f3a73f;
}

.danger {
	background-color: #e43d33;
}

.mb-50 {
	margin-bottom: 50rpx;
}

.empty-box {
	display: flex;
	flex-direction: column;
	margin-top: 50rpx;
}

.empty-box .title {
	color: #333;
	font-size: 36rpx;
	font-weight: bold;
	padding: 30rpx 0;
	text-align: center;
}

.empty-box .title-2 {
	color: #999;
	padding: 30rpx 0;
	font-size: 28rpx;
	border-bottom: 1px solid #b9b9b9;
}

.empty-box .empty-box-btn {
	display: flex;
	flex-direction: column;
}

.empty-box .empty-box-btn .icon {
	width: 50rpx;
	height: 50rpx;
	object-fit: cover;
	margin-right: 20rpx;
	padding: 15rpx 0;
}

.empty-box .empty-box-btn .empty-box-btn-item {
	display: flex;
	align-items: center;
	border-bottom: 1px solid #b9b9b9;
	padding: 15rpx 0;
}
</style>
